package edu.cth.ai23;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
//import java.util.LinkedList;
//import java.util.Queue;

public class RubiksCube implements IProblem {

    protected final static int dimension = 3;
    protected final static int xDimensionMultiplier = 4;
    protected final static int yDimensionMultiplier = 3;
    protected char[][] cubeStatus = new char[dimension * xDimensionMultiplier][dimension * yDimensionMultiplier];
    int heuristicChoice = 0;
    int problemSearchDepth = 5;
    boolean greed = false;
    String[] heuristicMethod = {"3D Manhattan Distance", "Corner+Edge Cubie misplacement", "3D Manhattan Distance + Corner+Edge Cubie misplacement", "Corner Cubie misplacement", "Edge Cubie misplacement", "Facelet misplacement"};
    {
        for (int i = 0; i < dimension * xDimensionMultiplier; i++) {
            for (int j = 0; j < dimension * yDimensionMultiplier; j++) {
                cubeStatus[i][j] = '0';
            }
        }
    }
    protected final static int[] xOffsets = {
        dimension, 0, dimension, 2 * dimension, 3 * dimension, dimension
    };
    protected final static int[] yOffsets = {
        0, dimension, dimension, dimension, dimension, 2 * dimension
    };
    private final static char[] initialColors = {
        'y', 'b', 'r', 'g', 'o', 'w'
    };
    private final static Color[] cubeColors = {
        Color.yellow, Color.blue, Color.red, Color.green,
        new Color(249, 127, 16), Color.white
    };

    public void handleKeyPress(int keyCode) {
        if (keyCode == KeyEvent.VK_F) {
            Transform.move(Transform.CubeCompositeMoves.f, this);
        } else if (keyCode == KeyEvent.VK_B) {
            Transform.move(Transform.CubeCompositeMoves.b, this);
        } else if (keyCode == KeyEvent.VK_R) {
            Transform.move(Transform.CubeCompositeMoves.r, this);
        } else if (keyCode == KeyEvent.VK_L) {
            Transform.move(Transform.CubeCompositeMoves.l, this);
        } else if (keyCode == KeyEvent.VK_U) {
            Transform.move(Transform.CubeCompositeMoves.u, this);
        } else if (keyCode == KeyEvent.VK_D) {
            Transform.move(Transform.CubeCompositeMoves.d, this);
        } else if (keyCode == KeyEvent.VK_H){
        	heuristicChoice++;
        	manhattanDistance3D();
        	if(heuristicChoice>5) {
        		heuristicChoice = 0;
        	}
        } else if (keyCode == KeyEvent.VK_Q) {
            this.problemSearchDepth++;
            if(this.problemSearchDepth > 10) {
            	this.problemSearchDepth = 1;
            }
        }
        else if (keyCode == KeyEvent.VK_G) {
            this.greed = (!this.greed);
        }
    }

    public void move(int moveIndex, IProblem problem) {
        Transform.move(Transform.CUBEVALUES[moveIndex], (RubiksCube) problem);
    }

    public void reverseMove(int moveIndex, IProblem problem) {
        Transform.move(Transform.CUBEVALUES[Transform.getReverseMoveIndex(moveIndex)], (RubiksCube) problem);
    }

    public void moveSequence(Integer[] moveIndexes, IProblem problem) {
        for (int i = 0; i < moveIndexes.length; i++) {
            Transform.move(Transform.CUBEVALUES[moveIndexes[i]], (RubiksCube) problem);
        }
    }

    public void reverseMoveSequence(Integer[] moveIndexes, IProblem problem) {
        for (int i = moveIndexes.length-1; i >= 0; i--) {

            int moveIndex = Transform.getReverseMoveIndex(moveIndexes[i]);
            //in any other case it is a 180 move, the same move again will restore the cube to its previous state
            Transform.move(Transform.CUBEVALUES[moveIndex], (RubiksCube) problem);
        }

    }

    public String getMoveName(int moveIndex) {
        return Transform.CUBEVALUES[moveIndex].toString();
    }

    public enum colors {

        r, g, b, w, y, o;
    }

    public RubiksCube() {
        reset();
    }

    public void reset() {

        for (int offsetIndex = 0; offsetIndex < 6; offsetIndex++) {
            for (int x = 0; x < dimension; x++) {
                for (int y = 0; y < dimension; y++) {
                    int xOffset = xOffsets[offsetIndex];
                    int yOffset = yOffsets[offsetIndex];

                    cubeStatus[x + xOffset][y + yOffset] = initialColors[offsetIndex];
                }
            }

        }

    }

    public void scramble() {
        for (int i = 0; i < 25; i++) {
            Transform.move(Transform.randMove(), this);
        }

    }

    
    /* 
     * The evaluation methods for the heuristics of Rubik's Cube
     */
    public int evaluate() {
        int fault = 0; //will always be 6 at the end
        //of the loop because the center facelet is
        //always the right color, so the least quality possible is
        // 6/dimension²
        switch (heuristicChoice) {
        case 0:
        	fault = this.manhattanDistance3D();
        	break;
        case 1:
        	fault = this.cornerCubieHeuristic() + this.edgeCubieHeuristic();
        	break;
        case 2:
            fault = this.manhattanDistance3D() + this.cornerCubieHeuristic() + this.edgeCubieHeuristic();
        	break;
        case 3:
        	fault = this.cornerCubieHeuristic();
        	break;
        case 4:
        	fault = this.edgeCubieHeuristic();
        	break;
        case 5:
        	for (int offsetIndex = 0; offsetIndex < 6; offsetIndex++) {
                for (int x = 0; x < dimension; x++) {
                    for (int y = 0; y < dimension; y++) {
                        int xOffset = xOffsets[offsetIndex];
                        int yOffset = yOffsets[offsetIndex];
                        if (cubeStatus[x + xOffset][y + yOffset] == initialColors[offsetIndex]) {
                            fault++;
                        }
                    }
                }
            }
        	fault = 54 - fault;
        }
        
        return fault;

    }
    
    public int manhattanDistance3D() {
    	int[] cornerCubies = new int[8];
    	int[] coordX = {0,2,0,0,2,2,2,0};
    	int[] coordY = {0,0,2,0,2,0,2,2};
    	int[] coordZ = {0,0,0,2,0,2,2,2};
    	//Calculate 3D Manhattan distance for the Rubik's Cube
    	/* start with the corner cubies: */
    	//0,0,0, coordinate 1:
    	cornerCubies[0] = (this.cubeStatus[0][5] * this.cubeStatus[3][8] * this.cubeStatus[11][5]);
    	cornerCubies[1] = (this.cubeStatus[5][8] * this.cubeStatus[8][5] * this.cubeStatus[9][5]);
    	cornerCubies[2] = (this.cubeStatus[3][5] * this.cubeStatus[2][5] * this.cubeStatus[3][6]);  
    	cornerCubies[3] = (this.cubeStatus[0][3] * this.cubeStatus[3][0] * this.cubeStatus[11][3]); 
    	cornerCubies[4] = (this.cubeStatus[5][5] * this.cubeStatus[6][5] * this.cubeStatus[5][6]); 
    	cornerCubies[5] = (this.cubeStatus[8][3] * this.cubeStatus[9][3] * this.cubeStatus[5][0]); 
    	cornerCubies[6] = (this.cubeStatus[5][2] * this.cubeStatus[5][3] * this.cubeStatus[6][3]);
    	cornerCubies[7] = (this.cubeStatus[3][3] * this.cubeStatus[3][2] * this.cubeStatus[2][3]);

        int distance = 0;
        for (int i=0; i<8; i++) {
        	switch (cornerCubies[i]) {
        	case 1294482: //1
        		distance += Math.abs(coordX[i]-0) + Math.abs(coordY[i]-0) + Math.abs(coordZ[i]-0);
        		break;
        	case 1360527: //2
        		distance += Math.abs(coordX[i]-2) + Math.abs(coordY[i]-0) + Math.abs(coordZ[i]-0);
        		break;
        	case 1329468: //3
        		distance += Math.abs(coordX[i]-0) + Math.abs(coordY[i]-2) + Math.abs(coordZ[i]-0);
        		break;
        	case 1316238: //4
        		distance += Math.abs(coordX[i]-0) + Math.abs(coordY[i]-0) + Math.abs(coordZ[i]-2);
        		break;
        	case 1397298: //5
        		distance += Math.abs(coordX[i]-2) + Math.abs(coordY[i]-2) + Math.abs(coordZ[i]-0);
        		break;
        	case 1383393: //6
        		distance += Math.abs(coordX[i]-2) + Math.abs(coordY[i]-0) + Math.abs(coordZ[i]-2);
        		break;
        	case 1420782: //7
        		distance += Math.abs(coordX[i]-2) + Math.abs(coordY[i]-2) + Math.abs(coordZ[i]-2);
        		break;
        	case 1351812: //8
        		distance += Math.abs(coordX[i]-0) + Math.abs(coordY[i]-2) + Math.abs(coordZ[i]-2);
        		break;
        	}
        }
        	
        	/* then we add the edge cubies */
        int[] edgeCubies = new int[12];
        int[] coordXEdge = {0,1,1,2,0,0,2,2,1,0,2,1};
        int[] coordYEdge = {0,0,0,0,1,1,1,1,2,2,2,2};
        int[] coordZEdge = {1,0,2,1,2,0,2,0,2,1,1,0};
        edgeCubies[0] = this.cubeStatus[0][4] * this.cubeStatus[11][4];
        edgeCubies[1] = this.cubeStatus[4][8] * this.cubeStatus[10][5];
        edgeCubies[2] = this.cubeStatus[4][0] * this.cubeStatus[10][3];
        edgeCubies[3] = this.cubeStatus[8][4] * this.cubeStatus[9][4];
        edgeCubies[4] = this.cubeStatus[3][1] * this.cubeStatus[1][3];
        edgeCubies[5] = this.cubeStatus[1][5] * this.cubeStatus[3][7];
        edgeCubies[6] = this.cubeStatus[5][1] * this.cubeStatus[7][3];
        edgeCubies[7] = this.cubeStatus[7][5] * this.cubeStatus[5][7];
        edgeCubies[8] = this.cubeStatus[4][2] * this.cubeStatus[4][3];
        edgeCubies[9] = this.cubeStatus[2][4] * this.cubeStatus[3][4];
        edgeCubies[10] = this.cubeStatus[5][4] * this.cubeStatus[6][4];
        edgeCubies[11] = this.cubeStatus[4][5] * this.cubeStatus[4][6];
        
        for (int i=0; i<12; i++) {
        	switch (edgeCubies[i]) {
        	case 10878: //0
        		distance += Math.abs(coordXEdge[i]-0) + Math.abs(coordYEdge[i]-0) + Math.abs(coordZEdge[i]-1);
        		break;
        	case 13209: //1
        		distance += Math.abs(coordXEdge[i]-1) + Math.abs(coordYEdge[i]-0) + Math.abs(coordZEdge[i]-0);
        		break;
        	case 13431: //2
        		distance += Math.abs(coordXEdge[i]-1) + Math.abs(coordYEdge[i]-0) + Math.abs(coordZEdge[i]-2);
        		break;
        	case 11433: //3
        		distance += Math.abs(coordXEdge[i]-2) + Math.abs(coordYEdge[i]-0) + Math.abs(coordZEdge[i]-1);
        		break;
        	case 11858: //4
        		distance += Math.abs(coordXEdge[i]-0) + Math.abs(coordYEdge[i]-1) + Math.abs(coordZEdge[i]-2);
        		break;
        	case 11662: //5
        		distance += Math.abs(coordXEdge[i]-0) + Math.abs(coordYEdge[i]-1) + Math.abs(coordZEdge[i]-0);
        		break;
        	case 12463: //6
        		distance += Math.abs(coordXEdge[i]-2) + Math.abs(coordYEdge[i]-1) + Math.abs(coordZEdge[i]-2);
        		break;
        	case 12257: //7
        		distance += Math.abs(coordXEdge[i]-2) + Math.abs(coordYEdge[i]-1) + Math.abs(coordZEdge[i]-0);
        		break;
        	case 13794: //8
        		distance += Math.abs(coordXEdge[i]-1) + Math.abs(coordYEdge[i]-2) + Math.abs(coordZEdge[i]-2);
        		break;
        	case 11172: //9
        		distance += Math.abs(coordXEdge[i]-0) + Math.abs(coordYEdge[i]-2) + Math.abs(coordZEdge[i]-1);
        		break;
        	case 11742: //10
        		distance += Math.abs(coordXEdge[i]-2) + Math.abs(coordYEdge[i]-2) + Math.abs(coordZEdge[i]-1);
        		break;
        	case 13566: //11
        		distance += Math.abs(coordXEdge[i]-1) + Math.abs(coordYEdge[i]-2) + Math.abs(coordZEdge[i]-0);
        		break;
        	}
        }
        
        return (distance/2);
    }
    
    public int edgeCubieHeuristic() {
    	int wrongCubies = 0;
    	//1-4
    	if ((this.cubeStatus[4][1] != this.cubeStatus[4][2]) || (this.cubeStatus[4][3] != this.cubeStatus[4][4])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[3][4] != this.cubeStatus[4][4]) || (this.cubeStatus[2][4] != this.cubeStatus[1][4])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[5][4] != this.cubeStatus[4][4]) || (this.cubeStatus[6][4] != this.cubeStatus[7][4])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[8][4] != this.cubeStatus[7][4]) || (this.cubeStatus[9][4] != this.cubeStatus[10][4])) {
    		wrongCubies++;
    	}
    	//5-8
    	if ((this.cubeStatus[11][4] != this.cubeStatus[10][4]) || (this.cubeStatus[0][4] != this.cubeStatus[1][4])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[4][1] != this.cubeStatus[5][1]) || (this.cubeStatus[7][3] != this.cubeStatus[7][4])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[3][1] != this.cubeStatus[4][1]) || (this.cubeStatus[1][3] != this.cubeStatus[1][4])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[3][7] != this.cubeStatus[4][7]) || (this.cubeStatus[1][4] != this.cubeStatus[1][5])) {
    		wrongCubies++;
    	}
    	//9-12
    	if ((this.cubeStatus[7][4] != this.cubeStatus[7][5]) || (this.cubeStatus[5][7] != this.cubeStatus[4][7])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[10][3] != this.cubeStatus[10][4]) || (this.cubeStatus[4][0] != this.cubeStatus[4][1])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[10][4] != this.cubeStatus[10][5]) || (this.cubeStatus[4][7] != this.cubeStatus[4][8])) {
    		wrongCubies++;
    	}
    	if ((this.cubeStatus[4][4] != this.cubeStatus[4][5]) || (this.cubeStatus[4][6] != this.cubeStatus[4][7])) {
    		wrongCubies++;
    	}
    	
    	return wrongCubies;
    }
    
    public int cornerCubieHeuristic() {
    	int wrongCubies = 0;
    	
    	if ((this.cubeStatus[3][3] != this.cubeStatus[4][4]) || 
    		(this.cubeStatus[3][3] != this.cubeStatus[4][4]) || 
    		(this.cubeStatus[3][3] != this.cubeStatus[4][4])) {
            	wrongCubies++;
        }
    	
    	if ((this.cubeStatus[4][1] != this.cubeStatus[5][2]) || 
    		(this.cubeStatus[5][3] != this.cubeStatus[4][4]) || 
    		(this.cubeStatus[6][3] != this.cubeStatus[7][4])) {
        	wrongCubies++;
    	}
    	
    	if ((this.cubeStatus[3][5] != this.cubeStatus[4][4]) || 
        	(this.cubeStatus[2][5] != this.cubeStatus[1][4]) || 
        	(this.cubeStatus[3][6] != this.cubeStatus[4][7])) {
            wrongCubies++;
        }
    	
    	if ((this.cubeStatus[5][5] != this.cubeStatus[4][4]) || 
        	(this.cubeStatus[6][5] != this.cubeStatus[7][4]) || 
        	(this.cubeStatus[5][6] != this.cubeStatus[4][7])) {
            wrongCubies++;
        }
    	
    	if ((this.cubeStatus[5][8] != this.cubeStatus[4][7]) || 
        	(this.cubeStatus[8][5] != this.cubeStatus[7][4]) || 
        	(this.cubeStatus[9][5] != this.cubeStatus[10][4])) {
            wrongCubies++;
        }
    	
    	if ((this.cubeStatus[8][3] != this.cubeStatus[7][4]) || 
       		(this.cubeStatus[9][3] != this.cubeStatus[10][4]) || 
       		(this.cubeStatus[5][0] != this.cubeStatus[4][1])) {
           	wrongCubies++;
        }
    	
    	if ((this.cubeStatus[0][3] != this.cubeStatus[1][4]) || 
           	(this.cubeStatus[3][0] != this.cubeStatus[4][1]) || 
           	(this.cubeStatus[11][3] != this.cubeStatus[10][4])) {
            wrongCubies++;
        }

    	if ((this.cubeStatus[0][5] != this.cubeStatus[1][4]) || 
        	(this.cubeStatus[3][8] != this.cubeStatus[4][7]) || 
        	(this.cubeStatus[11][5] != this.cubeStatus[10][4])) {
           	wrongCubies++;
        }
    	return wrongCubies;
    }
    
    public int crossHeuristic() {
        int h = 0;

        if (this.cubeStatus[1][4] != this.cubeStatus[1][5]) {
            h = h + 1;
        }
        if (this.cubeStatus[4][4] != this.cubeStatus[4][5]) {
            h = h + 1;
        }
        if (this.cubeStatus[7][4] != this.cubeStatus[7][5]) {
            h = h + 1;
        }
        if (this.cubeStatus[10][4] != this.cubeStatus[10][5]) {
            h = h + 1;
        }
        
        if (this.cubeStatus[4][6] != this.cubeStatus[4][7]) {
            h = h + 1;
        }
        if (this.cubeStatus[4][8] != this.cubeStatus[4][7]) {
            h = h + 1;
        }
        if (this.cubeStatus[3][7] != this.cubeStatus[4][7]) {
            h = h + 1;
        }
        if (this.cubeStatus[5][7] != this.cubeStatus[4][7]) {
            h = h + 1;
        }
        return h;
    }
    
    public int tHeuristic() {
        int h;
    	int h1 = 0;
        int h2 = 0;
        int h3 = 0;
        int h4 = 0;

        if (this.cubeStatus[2][5] != this.cubeStatus[1][4]) {
        	h1 = 1;
        }
        if (this.cubeStatus[3][5] != this.cubeStatus[4][4]) {
        	h1 = 1;
        }
        if (this.cubeStatus[3][6] != this.cubeStatus[4][7]) {
        	h1 = 1;
        }
        
        if (this.cubeStatus[5][5] != this.cubeStatus[4][4]) {
        	h2 = 1;
        }
        if (this.cubeStatus[5][6] != this.cubeStatus[4][7]) {
        	h2 = 1;
        }
        if (this.cubeStatus[6][5] != this.cubeStatus[7][4]) {
        	h2 = 1;
        }
        
        if (this.cubeStatus[8][5] != this.cubeStatus[7][4]) {
        	h3 = 1;
        }
        if (this.cubeStatus[9][5] != this.cubeStatus[10][4]) {
        	h3 = 1;
        }
        if (this.cubeStatus[5][8] != this.cubeStatus[4][7]) {
        	h3 = 1;
        }
        
        if (this.cubeStatus[0][5] != this.cubeStatus[1][4]) {
        	h4 = 1;
        }
        if (this.cubeStatus[3][8] != this.cubeStatus[4][7]) {
        	h4 = 1;
        }
        if (this.cubeStatus[11][5] != this.cubeStatus[10][4]) {
        	h4 = 1;
        }
        
        h = h1+h2+h3+h4;
        
        return h;
    }
    
    public int cornerHeuristic() {
        int h;
    	int h1 = 0;
        int h2 = 0;
//        int h3 = 0;
//        int h4 = 0;

        if (this.cubeStatus[3][3] != this.cubeStatus[4][4]) {
        	h1 = 1;
        }
        /*if (this.cubeStatus[2][3] != this.cubeStatus[1][4]) {
        	h1 = 1;
        }
        if (this.cubeStatus[3][2] != this.cubeStatus[4][1]) {
        	h1 = 1;
        }*/
        
        if (this.cubeStatus[5][3] != this.cubeStatus[4][4]) {
        	h2 = 1;
        }
        /*if (this.cubeStatus[5][2] != this.cubeStatus[4][1]) {
        	h2 = 1;
        }
        if (this.cubeStatus[6][3] != this.cubeStatus[7][4]) {
        	h2 = 1;
        }*/
        
        /*if (this.cubeStatus[0][3] != this.cubeStatus[1][4]) {
        	h3 = 1;
        }
        
        if (this.cubeStatus[8][3] != this.cubeStatus[7][4]) {
        	h4 = 1;
        }*/
        h = h1+h2;//+h3+h4;
        
        
        return h;
    }
    
    /*
     * End of Heuristic methods.
     */

    public void draw(Graphics g) {

        for (int offsetIndex = 0; offsetIndex < 6; offsetIndex++) {
            for (int x = 0; x < dimension; x++) {
                for (int y = 0; y < dimension; y++) {
                    int xOffset = xOffsets[offsetIndex];
                    int yOffset = yOffsets[offsetIndex];

                    int xPixel = (x + xOffset) * 50 + 100;
                    int yPixel = (y + yOffset) * 50 + 100;

                    char cubeColor = cubeStatus[x + xOffset][y + yOffset];

                    g.setColor(Color.black);
                    for (int i = 0; i < cubeColors.length; i++) {
                        if (cubeColor == initialColors[i]) {
                            g.setColor(cubeColors[i]);
                        }
                    }

                    g.fill3DRect(xPixel, yPixel, 50, 50, true);

                }
            }

        }

        g.setColor(Color.gray);
        g.drawString("Heuristic method: " + this.heuristicMethod[heuristicChoice] + " with " + this.evaluate() + " misplacements. Max search depth: " + this.problemSearchDepth + " greedy: " + this.greed, 10, 10);
        g.setColor(Color.white);
        g.drawString("Heuristic method: " + this.heuristicMethod[heuristicChoice] + " with " + this.evaluate() + " misplacements. Max search depth: " + this.problemSearchDepth + " greedy: " + this.greed, 10+1, 10+1);
      
    }
    protected static final ArrayList<Transform.CubeCompositeMoves> movesOrder = new ArrayList<Transform.CubeCompositeMoves>();

    static {
        movesOrder.add(Transform.CubeCompositeMoves.u);
        movesOrder.add(Transform.CubeCompositeMoves.d);
        movesOrder.add(Transform.CubeCompositeMoves.r);
        movesOrder.add(Transform.CubeCompositeMoves.l);
        movesOrder.add(Transform.CubeCompositeMoves.f);
        movesOrder.add(Transform.CubeCompositeMoves.b);
    }
    protected static final ArrayList<Transform.CubeCompositeMoves> reverseMovesOrder = new ArrayList<Transform.CubeCompositeMoves>();

    static {
        movesOrder.add(Transform.CubeCompositeMoves.u2);
        movesOrder.add(Transform.CubeCompositeMoves.d2);
        movesOrder.add(Transform.CubeCompositeMoves.r2);
        movesOrder.add(Transform.CubeCompositeMoves.l2);
        movesOrder.add(Transform.CubeCompositeMoves.f2);
        movesOrder.add(Transform.CubeCompositeMoves.b2);
    }

    public void copyValues(IProblem problem) {
        RubiksCube rc = (RubiksCube) problem; //assume that we get a RubiksCube problem
        this.heuristicChoice = rc.heuristicChoice;
        this.problemSearchDepth = rc.problemSearchDepth;
        this.greed = rc.greed;
        for (int offsetIndex = 0; offsetIndex < 6; offsetIndex++) {
            for (int x = 0; x < dimension; x++) {
                for (int y = 0; y < dimension; y++) {
                    int xOffset = xOffsets[offsetIndex];
                    int yOffset = yOffsets[offsetIndex];

                    this.cubeStatus[x + xOffset][y + yOffset] = rc.cubeStatus[x + xOffset][y + yOffset];
                }
            }

        }
    }

    public IProblem getProblemCopy() {
        RubiksCube rc = new RubiksCube();

        rc.copyValues((IProblem) this);
        return rc;
    }

    public int getSearchDepth() {
    	return this.problemSearchDepth;
    }
    
    public boolean getGreed() {
    	return this.greed;
    }
    
    public Integer[] getNoOfMoves(int previousIndex) {

        Integer[] movesIndexes = null;// new Integer[Transform.CUBEVALUES.length];
        //			  0 1 2  3  4  5  6  7  8  9
        //legal moves u d u2 d2 r2 l2 f2 b2 dp up
        switch (previousIndex) {
        case -1:
        	movesIndexes = new Integer[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        	break;
        case 0:
        	movesIndexes = new Integer[] {1, 3, 4, 5, 6, 7, 8};
        	break;
        case 1:
        	movesIndexes = new Integer[] {4, 5, 6, 7};
        	break;
        case 2:
        	movesIndexes = new Integer[] {1, 3, 4, 5, 6, 7, 8};
        	break;
        case 3:
        	movesIndexes = new Integer[] {4, 5, 6, 7};
        	break;
        case 4:
        	movesIndexes = new Integer[] {0, 1, 2, 3, 5, 6, 7, 8, 9};
        	break;
        case 5:
        	movesIndexes = new Integer[] {0, 1, 2, 3, 6, 7, 8, 9};
        	break;
        case 6:
        	movesIndexes = new Integer[] {0, 1, 2, 3, 4, 5, 7, 8, 9};
        	break;
        case 7:
        	movesIndexes = new Integer[] {0, 1, 2, 3, 4, 5, 8, 9};
        	break;
        case 8:
        	movesIndexes = new Integer[] {4, 5, 6, 7};
        	break;
        case 9:
        	movesIndexes = new Integer[] {1, 3, 4, 5, 6, 7, 8};
        	break;
        }
        /*if (previousIndex !=0) {
        	movesIndexes = new Integer[] {0, 1, 2, 3, 4, 5};
        }*/
        
        /*for (int i = 0; i < movesIndexes.length; i++) {
            movesIndexes[i] = i;
        }*/
        return movesIndexes;
    }
    
}
